Integrate OAT and SIU with Waypoints (#1060)
authorPacketFiend <kenneth@voort.ca>
Tue, 12 Sep 2023 11:28:55 +0000 (07:28 -0400)
committerGitHub <noreply@github.com>
Tue, 12 Sep 2023 11:28:55 +0000 (05:28 -0600)
* Integrate OAT and SIU with Waypoints

* Type corrections, convert set_value() overload to nullptr* check

* #1062 Fix core dump when merging tracks with disparate IGC extensions

* Reduce `value` variable scope when writing SimpleArrays

* Debug oopsie bugfix, fix core dump when merging IGC files with no extensions

* Collapse redundant if statement

* Fix brain fart

* Eliminate igc_fsdata::has_value()

* Fix subtle satellite count bug

* Fix small sat count bug, and eliminate some ifdefs

* Make some IGC exts override default WP members

* Include IGC line-by-line debug info

* Remove accidentally included file

* delete obsolete macros

---------

Co-authored-by: tsteven4 <13596209+tsteven4@users.noreply.github.com>
defs.h
igc.cc
igc.h
kml.cc
kml.h
reference/realtime.kml
reference/track/92GV66G1.igc.kml
reference/track/92HV66G1.igc.kml
waypt.cc

diff --git a/defs.h b/defs.h
index 2a337c3192eb76a41db142cb9f7cb5fc0efde674..18fe9c0cfa50041c9377b8971cf9062b655e40c5 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -261,13 +261,15 @@ public:
     trait_cadence(0),
     trait_power(0),
     trait_depth(0),
-    trait_temperature(0) {}
+    trait_temperature(0),
+    trait_sat(0) {}
   unsigned int trait_geocaches:1;
   unsigned int trait_heartrate:1;
   unsigned int trait_cadence:1;
   unsigned int trait_power:1;
   unsigned int trait_depth:1;
   unsigned int trait_temperature:1;
+  unsigned int trait_sat:1;
 };
 
 /*
diff --git a/igc.cc b/igc.cc
index 1910f291548e57ab91bc7e1b136ddd8f54adf27c..c26814354f5223107f04695f49339ab237f31b01 100644 (file)
--- a/igc.cc
+++ b/igc.cc
@@ -260,6 +260,9 @@ void IgcFormat::read()
   strcpy(trk_desc, HDRMAGIC HDRDELIM);
 
   while (true) {
+    if (global_opts.debug_level >= 8) {
+      printf(MYNAME ": Processing IGC file line %i\n", current_line);
+    }
     igc_rec_type_t rec_type = get_record(&ibuf);
     current_line++;
     QString ibuf_q = QString::fromUtf8(ibuf);
@@ -372,7 +375,7 @@ void IgcFormat::read()
         for (const auto& [name, ext, start, len, factor] : ext_types_list) {
           double ext_data = ibuf_q.mid(start,len).toInt() / factor;
 
-          fsdata->set_value(ext, ext_data);
+          fsdata->set_value(ext, ext_data, pres_wpt);
           if (global_opts.debug_level >= 6) {
             printf(" %s:%f", qPrintable(name), ext_data);
           }
diff --git a/igc.h b/igc.h
index 8646c1a1075dbd588e501b3501807adb6d3cc733..d0672811e5117c50fdc7be45def184a35544bf76 100644 (file)
--- a/igc.h
+++ b/igc.h
@@ -298,7 +298,8 @@ struct igc_fsdata : public FormatSpecificData {
   std::optional<double> acz; // Z Acceleration
   std::optional<double> gfo; // G Force?
 
-  bool set_value(IgcFormat::igc_ext_type_t type, double value)
+  // Stores all data as igc_fsdata
+  bool set_value(IgcFormat::igc_ext_type_t type, double value, Waypoint *wp = nullptr)
   {
     bool success = true;
     switch (type) {
@@ -312,6 +313,9 @@ struct igc_fsdata : public FormatSpecificData {
       vat = value;
       break;
     case IgcFormat::igc_ext_type_t::ext_rec_oat:
+      if (wp){
+        wp->set_temperature(value);
+      }
       oat = value;
       break;
     case IgcFormat::igc_ext_type_t::ext_rec_trt:
@@ -324,6 +328,9 @@ struct igc_fsdata : public FormatSpecificData {
       fxa = value;
       break;
     case IgcFormat::igc_ext_type_t::ext_rec_siu:
+      if (wp) {
+        wp->sat = value;
+      }
       siu = value;
       break;
     case IgcFormat::igc_ext_type_t::ext_rec_acz:
diff --git a/kml.cc b/kml.cc
index f05d86aa21741974dbf4e66fd82380c52b42528d..159cde986b5a69b635b6ce5c0b8568b761dd1076 100644 (file)
--- a/kml.cc
+++ b/kml.cc
@@ -69,8 +69,6 @@
 #define ICON_DIR ICON_BASE "track-directional/track-%1.png" // format string where next arg is rotational degrees.
 
 #define MYNAME "kml"
-// #define INCLUDE_IGC_TRT // Generally not very useful to graph on Google Earth
-// #define INCLUDE_IGC_SIU // Satellites in use, not entirely useful to graph
 
 void KmlFormat::kml_init_color_sequencer(unsigned int steps_per_rev)
 {
@@ -1496,6 +1494,10 @@ void KmlFormat::kml_mt_simple_array(const route_head* header,
       writer->writeTextElement(QStringLiteral("gx:value"), wpt->temperature_has_value()?
                                QString::number(wpt->temperature_value(), 'f', 1) : QString());
       break;
+    case wp_field::sat:
+      writer->writeTextElement(QStringLiteral("gx:value"), wpt->sat >= 0?
+                                QString::number(wpt->sat) : QString());
+      break;
     case wp_field::igc_enl:
     case wp_field::igc_tas:
     case wp_field::igc_vat:
@@ -1561,6 +1563,7 @@ void KmlFormat::kml_mt_hdr(const route_head* header)
   bool has_heartrate = false;
   bool has_temperature = false;
   bool has_power = false;
+  bool has_sat = false;
   bool has_igc_exts = false;
   bool has_igc_enl = false;
   bool has_igc_tas = false;
@@ -1570,12 +1573,8 @@ void KmlFormat::kml_mt_hdr(const route_head* header)
   bool has_igc_fxa = false;
   bool has_igc_gfo = false;
   bool has_igc_acz = false;
-#ifdef INCLUDE_IGC_SIU
   bool has_igc_siu = false; // Not very useful to graph
-#endif
-#ifdef INCLUDE_IGC_TRT // Not very useful to graph
-  bool has_igc_trt = false;
-#endif
+  bool has_igc_trt = false; // Not very useful to graph
 
   // This logic is kind of inside-out for GPSBabel.  If a track doesn't
   // have enough interesting timestamps, just write it as a LineString.
@@ -1635,6 +1634,10 @@ void KmlFormat::kml_mt_hdr(const route_head* header)
     if (tpt->power) {
       has_power = true;
     }
+    // # of satellites can legitimately be zero, so -1 means no data in this case
+    if (tpt->sat >= 0) {
+      has_sat = true;
+    }
     if (fs_igc) {
       has_igc_exts = true;
       if (fs_igc->enl.has_value()) {
@@ -1661,47 +1664,29 @@ void KmlFormat::kml_mt_hdr(const route_head* header)
       if (fs_igc->acz.has_value()) {
         has_igc_acz = true;
       }
-#ifdef INCLUDE_IGC_SIU
-      if (fs_igc->siu.has_value()) {
-        has_igc_siu = true;
+      if constexpr(kIncludeIGCSIU) {
+        if (fs_igc->siu.has_value()) {
+          has_igc_siu = true;
+        }
       }
-#endif
-#ifdef INCLUDE_IGC_TRT
-      if (fs_igc->trt.has_value()) {
-        has_igc_trt = true;
+      if constexpr(kIncludeIGCTRT) {
+        if (fs_igc->trt.has_value()) {
+          has_igc_trt = true;
+        }
       }
-#endif
     }
   }
 
   // This gets unwieldly if we check each individual igc extension,
   // hence the has_igc_exts flag.
   if (has_cadence || has_depth || has_heartrate || has_temperature ||
-      has_power || has_igc_exts) {
+      has_power || has_sat || has_igc_exts) {
+    bool include_kmt_sats = true;
+    bool include_kmt_temperature = true;
     writer->writeStartElement(QStringLiteral("ExtendedData"));
     writer->writeStartElement(QStringLiteral("SchemaData"));
     writer->writeAttribute(QStringLiteral("schemaUrl"), QStringLiteral("#schema"));
 
-    if (has_cadence) {
-      kml_mt_simple_array(header, kmt_cadence, wp_field::cadence);
-    }
-
-    if (has_depth) {
-      kml_mt_simple_array(header, kmt_depth, wp_field::depth);
-    }
-
-    if (has_heartrate) {
-      kml_mt_simple_array(header, kmt_heartrate, wp_field::heartrate);
-    }
-
-    if (has_temperature) {
-      kml_mt_simple_array(header, kmt_temperature, wp_field::temperature);
-    }
-
-    if (has_power) {
-      kml_mt_simple_array(header, kmt_power, wp_field::power);
-    }
-
     // Perhaps not the /best/ way to do this, but this if ladder
     // should only be evaluated once.
     if (has_igc_exts) {
@@ -1713,6 +1698,7 @@ void KmlFormat::kml_mt_hdr(const route_head* header)
       }
       if (has_igc_oat) {
         kml_mt_simple_array(header, kmt_igc_oat, wp_field::igc_oat);
+        include_kmt_temperature = false;
       }
       if (has_igc_vat) {
         kml_mt_simple_array(header, kmt_igc_vat, wp_field::igc_vat);
@@ -1729,16 +1715,41 @@ void KmlFormat::kml_mt_hdr(const route_head* header)
       if (has_igc_acz) {
         kml_mt_simple_array(header, kmt_igc_acz, wp_field::igc_acz);
       }
-#ifdef INCLUDE_IGC_SIU
-      if (has_igc_siu) {
-        kml_mt_simple_array(header, kmt_igc_siu, igc_siu);
+      if constexpr(kIncludeIGCSIU) {
+        if (has_igc_siu) {
+          kml_mt_simple_array(header, kmt_igc_siu, wp_field::igc_siu);
+          include_kmt_sats = false;
+        }
       }
-#endif
-#ifdef INCLUDE_IGC_TRT
-      if (has_igc_trt) {
-        kml_mt_simple_array(header, kmt_igc_trt, igc_trt);
+      if constexpr(kIncludeIGCTRT) {
+        if (has_igc_trt) {
+          kml_mt_simple_array(header, kmt_igc_trt, wp_field::igc_trt);
+        }
       }
-#endif
+    }
+
+    if (has_cadence) {
+      kml_mt_simple_array(header, kmt_cadence, wp_field::cadence);
+    }
+
+    if (has_depth) {
+      kml_mt_simple_array(header, kmt_depth, wp_field::depth);
+    }
+
+    if (has_heartrate) {
+      kml_mt_simple_array(header, kmt_heartrate, wp_field::heartrate);
+    }
+
+    if (has_temperature && include_kmt_temperature) {
+      kml_mt_simple_array(header, kmt_temperature, wp_field::temperature);
+    }
+
+    if (has_power) {
+      kml_mt_simple_array(header, kmt_power, wp_field::power);
+    }
+
+    if (has_sat && include_kmt_sats) {
+      kml_mt_simple_array(header, kmt_sat, wp_field::sat);
     }
 
     writer->writeEndElement(); // Close SchemaData tag
@@ -1924,7 +1935,8 @@ void KmlFormat::write()
       traits->trait_cadence ||
       traits->trait_power ||
       traits->trait_temperature ||
-      traits->trait_depth) {
+      traits->trait_depth ||
+      traits->trait_sat) {
     writer->writeStartElement(QStringLiteral("Schema"));
     writer->writeAttribute(QStringLiteral("id"), QStringLiteral("schema"));
 
@@ -1943,6 +1955,9 @@ void KmlFormat::write()
     if (traits->trait_depth) {
       kml_mt_array_schema(kmt_depth, "Depth", "float");
     }
+    if (traits->trait_sat) {
+      kml_mt_array_schema(kmt_sat, "Satellites", "int");
+    }
     writer->writeEndElement(); // Close Schema tag
   }
 
diff --git a/kml.h b/kml.h
index f11e2ebbd81a3c3b4a7108c6e249fff3e4f3c58b..505e7aeac1c79f743262581e3d1b9cf43493a8ce 100644 (file)
--- a/kml.h
+++ b/kml.h
@@ -74,6 +74,7 @@ public:
     heartrate,
     temperature,
     power,
+    sat,
     igc_enl,  // Engine Noise Level
     igc_tas,  // True Airspeed
     igc_vat,  // Compensated variometer (total energy)
@@ -123,6 +124,7 @@ private:
   static constexpr const char* kmt_temperature = "temperature";
   static constexpr const char* kmt_depth = "depth";
   static constexpr const char* kmt_power = "power";
+  static constexpr const char* kmt_sat = "satellites";
   // Constants pertaining to IGC files would be better defined in either igc.h or formspec.h
   static constexpr const char* kmt_igc_enl = "Engine Noise";
   static constexpr const char* kmt_igc_vat = "Ttl Enrg Vario";
@@ -135,6 +137,10 @@ private:
   static constexpr const char* kmt_igc_siu = "# Of Sats";
   static constexpr const char* kmt_igc_acz = "Z Accel";
 
+  // IGC option compile-time flags
+  static constexpr bool kIncludeIGCSIU = true;
+  static constexpr bool kIncludeIGCTRT = false;
+
   /* Member Functions */
 
   void kml_init_color_sequencer(unsigned int steps_per_rev);
index 1eb65120f1e650f83f2274038c210662d8d9a7ec..11a9142490ae2068a6346dd4c081d8da9e24e0de 100644 (file)
       <gx:SimpleArrayField name="depth" type="float">
         <displayName>Depth</displayName>
       </gx:SimpleArrayField>
+      <gx:SimpleArrayField name="satellites" type="int">
+        <displayName>Satellites</displayName>
+      </gx:SimpleArrayField>
     </Schema>
     <Placemark>
       <name>Wpt_8u4Dqkf</name>
               <gx:value>402.7</gx:value>
               <gx:value></gx:value>
             </gx:SimpleArrayData>
+            <gx:SimpleArrayData name="satellites">
+              <gx:value>6</gx:value>
+              <gx:value>8</gx:value>
+              <gx:value>6</gx:value>
+              <gx:value>3</gx:value>
+              <gx:value>12</gx:value>
+              <gx:value>11</gx:value>
+              <gx:value>3</gx:value>
+              <gx:value>4</gx:value>
+              <gx:value>10</gx:value>
+              <gx:value>4</gx:value>
+              <gx:value>10</gx:value>
+              <gx:value>9</gx:value>
+              <gx:value>8</gx:value>
+              <gx:value>9</gx:value>
+              <gx:value>2</gx:value>
+              <gx:value>3</gx:value>
+              <gx:value>5</gx:value>
+            </gx:SimpleArrayData>
           </SchemaData>
         </ExtendedData>
       </gx:Track>
index 5e325be058eda42f7f21cd3a3d8d0961c177eab0..046376dfb4f1fc05653315e12ce637ce7dfc5dba 100644 (file)
         <width>6</width>
       </LineStyle>
     </Style>
+    <Schema id="schema">
+      <gx:SimpleArrayField name="temperature" type="float">
+        <displayName>Temperature</displayName>
+      </gx:SimpleArrayField>
+    </Schema>
     <Folder>
       <name>Tracks</name>
       <Placemark>
index 91600f9377869f5bf598fd9591b2371c9331deea..e5957a366b958dd6921aa7dfdbc3c251f0956e53 100644 (file)
         <width>6</width>
       </LineStyle>
     </Style>
+    <Schema id="schema">
+      <gx:SimpleArrayField name="temperature" type="float">
+        <displayName>Temperature</displayName>
+      </gx:SimpleArrayField>
+    </Schema>
     <Folder>
       <name>Tracks</name>
       <Placemark>
index 30b255c73435012d2ae5f40b25cb545ed80c27cf..e7f45e08cefe9108295c3f850c5a1778f18365af 100644 (file)
--- a/waypt.cc
+++ b/waypt.cc
@@ -74,6 +74,7 @@ void update_common_traits(const Waypoint* wpt)
   traits.trait_power |= wpt->power > 0;
   traits.trait_depth |= wpt->depth_has_value();
   traits.trait_temperature |= wpt->temperature_has_value();
+  traits.trait_sat |= wpt->sat >= 0;
 }
 
 void